package com.hh.demo.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.hh.demo.constants.CommonConstants;
import com.hh.demo.constants.DemoError;
import com.hh.demo.constants.ImgCodeConstants;
import com.hh.demo.constants.TelCodeConstants;
import com.hh.demo.domain.MessageSms;
import com.hh.demo.domain.MessageSmsBlack;
import com.hh.demo.dto.RedisTelCodeDto;
import com.hh.demo.dto.TelCodeDto;
import com.hh.demo.feignClient.UserFeignClient;
import com.hh.demo.result.JSONResult;
import com.hh.demo.service.IMessageSmsBlackService;
import com.hh.demo.service.IMessageSmsService;
import com.hh.demo.service.IVerifyCodeService;
import com.hh.demo.util.AssertUtil;
import com.hh.demo.util.StrUtils;
import com.hh.demo.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author 黄浩
 * @create 2022-06-15 16:46
 */
@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    @Resource
    private RedisTemplate<Object,Object> redisTemplate;
    @Resource
    private UserFeignClient userFeignClient;
    @Resource
    private TelCodeConstants telCodeConstants;
    @Resource
    private ImgCodeConstants imgCodeConstants;
    @Resource
    private IMessageSmsService messageSmsService;
    @Resource
    private IMessageSmsBlackService messageSmsBlackService;
    /**
     * 得到uuid，返回base64码
     * @return
     */
    @Override
    public String image(String imageCodeKey) {
        String code = StrUtils.getComplexRandomString(imgCodeConstants.getSize());
        redisTemplate.opsForValue().set(imageCodeKey, code, imgCodeConstants.getTimeout(), TimeUnit.SECONDS);
        return VerifyCodeUtils.verifyCode(100, 40, code);
    }

    /**
     * 发送验证码的方法，根据type不同，发送不同的验证码
     * @param telCodeDto
     */
    @Override
    public void sendTelCode(TelCodeDto telCodeDto) {
        String type = telCodeDto.getType();
        switch (type){
            case CommonConstants.TYPE_REGISTER :
                registerTelCode(telCodeDto);
                break;
        }
    }

    private void registerTelCode(TelCodeDto telCodeDto) {
        String tel = telCodeDto.getMobile();
        String imageCodeKey = telCodeDto.getImageCodeKey();
        String imageCodeValue = telCodeDto.getImageCode();
        Object imageCodeObj = redisTemplate.opsForValue().get(imageCodeKey);

        AssertUtil.isNotNull(imageCodeObj, DemoError.COMMON_IMG_CODE_NULL.getMessage());
        AssertUtil.isEqualsIgnoreCase(imageCodeObj.toString(),imageCodeValue,DemoError.COMMON_IMG_CODE_ERROR.getMessage());

        JSONResult jsonResult = userFeignClient.getUserByTel(tel);
        AssertUtil.isNull(jsonResult.getData(),DemoError.COMMON_TEL_EXISTS.getMessage());

        //获取request，从而获取ip
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        String ip = request.getRemoteAddr();
        //判断账号和ip是否被拉黑
        MessageSmsBlack black = selectBlack(ip,tel,null);
        AssertUtil.isNull(black, DemoError.COMMON_BLACK_EXISTS.getMessage());
        //拼接存入redis的key
        String key = String.format(CommonConstants.REGISTER_TEL_PREFIX,tel);
        toSendCode(key,tel);
    }

    private void toSendCode(String key,String tel) {
        Object telCodeObj = redisTemplate.opsForValue().get(key);
        String telCode = "";
        Date now;
        if (telCodeObj == null) {
            //没有该号码对应的验证码，生成一个并赋给它
            telCode = StrUtils.getRandomString(telCodeConstants.getSize());
        } else {
            //存在该号码对应的验证码了
            //获取验证码的间隔小于一分钟->有人搞事
            RedisTelCodeDto telCodeDto = (RedisTelCodeDto)telCodeObj;
            boolean flag = (System.currentTimeMillis() - telCodeDto.getTime())/1000 > telCodeConstants.getInterval();
            AssertUtil.isTrue(flag,DemoError.COMMON_SERIOUS.getMessage());
            //获取验证码的间隔大于一分钟，还是用老验证码，只是更新一下时间戳
            telCode = telCodeDto.getCode();
        }
        //将dto对象存进redis
        now = new Date();
        RedisTelCodeDto redisTelCodeDto = new RedisTelCodeDto(telCode, now.getTime());
        redisTemplate.opsForValue().set(key,redisTelCodeDto,telCodeConstants.getTimeout(),TimeUnit.SECONDS);
        //发短信
        //SendCodeUtil.sendCode(tel,telCode);
        String message = String.format(telCodeConstants.getTelmessage(), telCode);
        log.info(message);
        //存储发送信息到数据库
        saveMessageSms(now,message,tel);
    }

    private void saveMessageSms(Date now,String message,String tel) {
        MessageSms messageSms = new MessageSms();
        messageSms.setTel(tel);
        messageSms.setContent(message);
        messageSms.setSendTime(now);
        messageSms.setTitle(telCodeConstants.getTitle());
        //获取request，从而获取ip
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        messageSms.setIp(request.getRemoteAddr());
        messageSmsService.insert(messageSms);
    }
    /**
     * 检验是否已被拉黑
     */
    private MessageSmsBlack selectBlack(String ip,String tel,Long userId){
        return messageSmsBlackService.selectOne(new EntityWrapper<MessageSmsBlack>()
                .or().eq("ip", ip)
                .or().eq("tel",tel)
                .or().eq("user_id",userId)
        );
    }
}
